import os
import Plugin
import dbus

import emesenelib.common

class MainClass(Plugin.Plugin):    
    def __init__(self, controller, msn):
        Plugin.Plugin.__init__(self, controller, msn)
        
        self.description = _('This plugin will show the number of unread messages for open conversation windows in AWN taskbar')
        self.authors = {'Re\'em Bensimhon' : 'reem.bs@gmail.com'}
        self.website = ''
        self.displayName = _('Awn Unread Plugin')
        self.name = 'AwnPlugin'
        
        self.eventManager = {} # stores all the event handles per internal window Id
        self.windowIndex = 0  # seq num to internaly identify the opened windows
        self.conversationMonitor = {} # stores internal win id and unread messages per conversation title
        self.awn_ok = False
        
    def start( self ):
        self.initAWN()
        self.rec = self.controller.conversationManager.connect('receive-message', 
                                                               self.updateUnreadCount);
        self.clearAllConversations();
        self.enabled = True
    
    def check( self ):
        return (True, 'Ok')
    
    def stop( self ):
        self.clearAllConversations();
        self.controller.conversationManager.disconnect(self.rec);
        self.enabled = False
        
    # clean up all conversation
    def clearAllConversations( self ):
        if len(self.conversationMonitor.keys()) > 0:
            for wnd, conv in self.controller.conversationManager.conversations:
                id = conv.getTitle()
                if id in self.conversationMonitor.keys():
                    winId, msgs = self.conversationMonitor[id]
                    self.conversationMonitor[id] = winId, 0
                    self.updateAwn(conv)
                    
                    if winId in self.eventManager.keys():
                        foc, swt, clo = self.eventManager[winId]
                        conv.parentConversationWindow.disconnect(foc)
                        conv.parentConversationWindow.tabs.disconnect(swt)
                        conv.parentConversationWindow.disconnect(clo)
                        self.eventManager.pop(winId)
                        
                    self.conversationMonitor.pop(id)
        
        self.conversationMonitor = {}
        self.eventManager = {}
        
    # event hadler for the new message event
    def updateUnreadCount(self, cm, conversation, mail, nick, message, format, charset):
        win = conversation.parentConversationWindow
        if win and (not win.has_toplevel_focus() or not conversation.isCurrent):
       
            # The checkWindowExists func. will see if this is a new window or just
            # a new message that belongs to an existing window
            winId, msgs = self.checkWindowExists(conversation)
            
            if winId == None: # This is the first message in the window
                winId = self.getWindowId(conversation)
                
                #Register all reading events 
                foc = win.connect('focus-in-event', self.readMsgs)
                swt = win.tabs.connect('switch-page', self.readMsgsSwitch)
                clo = win.connect('hide', self.unbind)
                
                # Save handles per window along with the number of new messages
                # in the window
                self.eventManager[winId] = foc, swt, clo
            else: # This isn't the first conversation in the window.
                self.conversationMonitor[conversation.getTitle()] = winId, msgs + 1
                
            self.updateAwn(conversation)
    
    # event hadler for the window close
    def unbind (self, widget):
        win = widget.conversation.parentConversationWindow
        winId, msgs = self.checkWindowExists(widget.conversation)
        
        for c in win.conversations:
            id = c.getTitle()

            if winId in self.eventManager.keys():
                foc, swt, clo = self.eventManager[winId]
                
                #disconnect all events from window
                win.disconnect(foc)
                win.disconnect(clo)
                win.tabs.disconnect(swt)
                
                self.eventManager.pop(winId)
                
            if id in self.conversationMonitor.keys():
                self.conversationMonitor.pop(id)            

    # searches all open conversations in window for one that already exists in
    # the conversationMonitor dictionary and if found adds it to the dictionary with the
    # same windowId as the matching conversation and returns the windowId
    def checkWindowExists (self, conversation):
        if conversation.getTitle() not in self.conversationMonitor.keys():
            convs = conversation.parentConversationWindow.conversations
            for t in self.conversationMonitor.keys():
                for c in convs:
                    if c.getTitle() == t:
                        title = conversation.getTitle()
                        self.conversationMonitor[title] = self.conversationMonitor[t][0], 0
                        return self.conversationMonitor[title]
            return None, 0
        else:
            return self.conversationMonitor[conversation.getTitle()]
    
    # func. called in case a new window shows. It assigns the window with it's own
    # internal id and defaults the num of msgs to one new message
    def getWindowId ( self, conversation ):
        self.windowIndex = self.windowIndex + 1
        self.conversationMonitor[conversation.getTitle()] = self.windowIndex - 1, 1
        return (self.windowIndex - 1)
    
    # event handler for the window focus event
    def readMsgs (self, widget, event):
        self.readMsgsGeneric(widget.conversation, widget.conversation.getTitle())
        #emesenelib.common.debug('readMsgs called')
    
    # event handler for the switch tab event
    def readMsgsSwitch(self, _notebook, _page, page_num):
        conversation = _notebook.get_nth_page(page_num).parentConversation
        title = _notebook.get_nth_page(_notebook.current_page()).parentConversation.getTitle()
        self.readMsgsGeneric(conversation, title)
        
    # func. called when window is marked as read. doesn't mean that all
    # conversations in the window were read
    def readMsgsGeneric (self, conversation, title):
        id = conversation.getTitle()
                
        if id in self.conversationMonitor.keys():
            winId, msgs = self.conversationMonitor[id]
            if msgs != 0:
                self.conversationMonitor[id] = winId, 0
                self.updateAwn(conversation, title)
        else:
            emesenelib.common.debug('AWN plugin: Error: read event attached to window that doesn\'t exist in the conversationMonitor')
    
    # initialize AWN
    def initAWN(self):
        self.awn_ok = False
        bus = dbus.SessionBus()
        try:
            obj = bus.get_object("com.google.code.Awn", "/com/google/code/Awn")
            self.awn_ok = True
        except dbus.DBusException:
            self.awn_ok = False
        if self.awn_ok:
            self.awn = dbus.Interface(obj, "com.google.code.Awn")
    
    # This function tells awn to pring a new number of messages for window
    # title argument should be the current title of the window (not conversation)
    def updateAwn(self, conversation, tabTitle=None):
        if self.awn_ok:
            try:
                msgs, title = self.getUnreadCountForWindow(conversation.parentConversationWindow)
                if tabTitle != None:
                    title = tabTitle
                if msgs == 0:                    
                    self.awn.UnsetInfoByName(title)
                else:
                    self.awn.SetInfoByName(title,'%(#)d' % {"#": msgs})
            
            except dbus.DBusException:
                self.awn_ok = False
        else:
            self.initAWN()
    
    def getUnreadCountForWindow (self, window):
        count = 0
        for conv in window.conversations:
            title = conv.getTitle()
            if title in self.conversationMonitor.keys():
                winId, msgs = self.conversationMonitor[title]
                count = count + msgs
        return count, window.title